package cn.com.egova.erp.biz.impl;

import cn.com.egova.erp.biz.IOrdersBiz;
import cn.com.egova.erp.dao.IEmpDao;
import cn.com.egova.erp.dao.IOrdersDao;
import cn.com.egova.erp.dao.ISupplierDao;
import cn.com.egova.erp.entity.Emp;
import cn.com.egova.erp.entity.Orderdetail;
import cn.com.egova.erp.entity.Orders;
import cn.com.egova.erp.entity.Supplier;
import cn.com.egova.erp.exception.ErpException;
import com.redsun.bos.ws.Waybilldetail;
import com.redsun.bos.ws.impl.IWaybillWs;
import net.sf.jxls.transformer.XLSTransformer;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.core.io.ClassPathResource;

import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 订单业务逻辑类
 *
 * @author Administrator
 */
public class OrdersBiz extends BaseBiz<Orders> implements IOrdersBiz {
    private IOrdersDao ordersDao;
    private IEmpDao empDao;
    private ISupplierDao supplierDao;
    private IWaybillWs waybillWs;

    public void setOrdersDao(IOrdersDao ordersDao) {
        this.ordersDao = ordersDao;
        super.setBaseDao(this.ordersDao);
    }

    public void setEmpDao(IEmpDao empDao) {
        this.empDao = empDao;
    }

    public void setSupplierDao(ISupplierDao supplierDao) {
        this.supplierDao = supplierDao;
    }

    public void setWaybillWs(IWaybillWs waybillWs) {
        this.waybillWs = waybillWs;
    }

    @Override
    public void add(Orders orders) {
        //Subjejct可以理解为当前登录用户
        Subject subject = SecurityUtils.getSubject();
        if (Orders.TYPE_IN.equals(orders.getType())) {
            if (!subject.isPermitted("我的销售订单")) {
                throw new ErpException("权限不足");
            }
        } else if (Orders.TYPE_OUT.equals(orders.getType())) {
            if (!subject.isPermitted("我的销售订单")) {
                throw new ErpException("权限不足");
            }
        } else {
            throw new ErpException("参数不合法");
        }
        //设置订单状态
        orders.setState(Orders.STATE_CREATE);
        //设置下单时间
        orders.setCreatetime(new Date());
        double total = 0;
        for (Orderdetail detail : orders.getOrderDetails()) {
            //累计金额
            total += detail.getMoney();
            //订单明细状态
            detail.setState(Orderdetail.STATE_NOT_IN);
            //设置订单明细与订单的关系
            detail.setOrders(orders);
        }
        //设置累计金额
        orders.setTotalmoney(total);
        //保存
        ordersDao.add(orders);
    }


    @Override
    public List<Orders> getListByPage(Orders orders1, Orders orders2, Object param, int firstResult, int maxResults) {
        //获取分页后的订单列表
        List<Orders> ordersList = super.getListByPage(orders1, orders2, param, firstResult, maxResults);
        //缓存员工编号和员工名称
        Map<Long, String> empNameMap = new HashMap<>();
        Map<Long, String> supplierNameMap = new HashMap<>();
        //循环获取员工名称
        for (Orders orders : ordersList) {
            orders.setCreaterName(getEmpName(orders.getCreater(), empNameMap));
            orders.setCheckerName(getEmpName(orders.getChecker(), empNameMap));
            orders.setStarterName(getEmpName(orders.getStarter(), empNameMap));
            orders.setEnderName(getEmpName(orders.getEnder(), empNameMap));
            orders.setSupplierName(getSupplierName(orders.getSupplieruuid(), supplierNameMap));
        }

        return ordersList;
    }


    /**
     * 根据员工编号获取员工名称并缓存
     *
     * @param uuid
     * @param empNameMap
     * @return
     */

    private String getEmpName(Long uuid, Map<Long, String> empNameMap) {
        if (uuid == null) {
            return null;
        }
        String empName = empNameMap.get(uuid);
        if (empName == null) {
            //数据库查询
            Emp emp = empDao.get(uuid);
            if (emp != null) {
                empName = emp.getName();
                //放入缓存
                empNameMap.put(uuid, empName);
            }
        }
        return empName;
    }

    /**
     * 根据供应商编号获取员工名称并缓存
     *
     * @param uuid
     * @param supplierNameMap
     * @return
     */
    private String getSupplierName(Long uuid, Map<Long, String> supplierNameMap) {
        if (uuid == null) {
            return null;
        }
        String supplierName = supplierNameMap.get(uuid);
        if (supplierName == null) {
            //数据库查询
            Supplier supplier = supplierDao.get(uuid);
            if (supplier != null) {
                supplierName = supplier.getName();
                //放入缓存
                supplierNameMap.put(uuid, supplierName);
            }
        }
        return supplierName;
    }

    @Override
    @RequiresPermissions("采购订单审核")
    public void doCheck(Long uuid, Long empUuid) {
        //获取订单，进入持久化状态
        Orders orders = ordersDao.get(uuid);
        if (!Orders.STATE_CREATE.equals(orders.getState())) {
            throw new ErpException("该订单已审核过");  //上层调用者需要捕获该异常
        }
        //修改订单状态
        orders.setState(Orders.STATE_CHECK);
        //设置审核人、审核时间
        orders.setChecker(empUuid);
        orders.setChecktime(new Date());
    }

    @Override
    public void doStart(Long uuid, Long empUuid) {
        //获取订单，进入持久化状态
        Orders orders = ordersDao.get(uuid);
        if (!Orders.STATE_CHECK.equals(orders.getState())) {
            throw new ErpException("该订单已确认过");
        }
        //修改订单状态
        orders.setState(Orders.STATE_START);
        //设置确认人、确认时间
        orders.setStarter(empUuid);
        orders.setStarttime(new Date());
    }

    @Override
    public void export(OutputStream os, Long uuid) {
        //查询订单及明细
        Orders orders = ordersDao.get(uuid);
        List<Orderdetail> detailList = orders.getOrderDetails();
        String sheetName = "";
        String supplierOrCustomer = "";
        if (Orders.TYPE_IN.equals(orders.getType())) {
            sheetName = "采购单";
            supplierOrCustomer = "供应商";
        }
        if (Orders.TYPE_OUT.equals(orders.getType())) {
            sheetName = "销售单";
            supplierOrCustomer = "客户";
        }

        //创建工作簿
        HSSFWorkbook wb = new HSSFWorkbook();
        //创建工作表
        HSSFSheet sheet = wb.createSheet(sheetName);

        //创建第一行(标题行),行的索引是从0开始
        HSSFRow row = sheet.createRow(0);
        //创建标题样式(对齐、字体等)
        HSSFCellStyle style_title = wb.createCellStyle();
        style_title.setAlignment(HorizontalAlignment.CENTER);
        style_title.setVerticalAlignment(VerticalAlignment.CENTER);
        HSSFFont font_title = wb.createFont();
        font_title.setFontName("黑体");
        font_title.setBold(true);
        font_title.setFontHeightInPoints((short) 18);
        style_title.setFont(font_title);
        //设置标题样式，注意第一个单元格并未创建，需要创建出来
        sheet.getRow(0).createCell(0).setCellStyle(style_title);

        //创建内容样式
        //设置边框
        HSSFCellStyle style_content = wb.createCellStyle();
        style_content.setBorderTop(BorderStyle.THIN);
        style_content.setBorderRight(BorderStyle.THIN);
        style_content.setBorderBottom(BorderStyle.THIN);
        style_content.setBorderLeft(BorderStyle.THIN);
        //设置对齐和字体
        style_content.setAlignment(HorizontalAlignment.CENTER);       //水平居中
        style_content.setVerticalAlignment(VerticalAlignment.CENTER); //垂直居中
        HSSFFont font_Content = wb.createFont();          //创建字体
        font_Content.setFontName("宋体");                  //字体名称
        font_Content.setFontHeightInPoints((short) 11);    //字体大小
        style_content.setFont(font_Content);               //设置样式的字体

        //合并单元格
        //第一行是显示订单的标题：比如显示为 “采购订单”，需要合并A、B、C、D列。
        //第3行的B、C、D列，需要合并成一个单元格，用来显示供应商的名称
        //第8行，需要合并成一个单元格，用来显示“订单详情”
        //firstRow, lastRow, firstColumn, lastColumn
        sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 3));   //标题
        sheet.addMergedRegion(new CellRangeAddress(2, 2, 1, 3));   //供应商
        sheet.addMergedRegion(new CellRangeAddress(7, 7, 0, 3));   //订单明细

        //根据订单创建单元格并设置样式
        int rowCount = detailList.size() + 9;
        for (int i = 2; i <= rowCount; i++) {
            row = sheet.createRow(i);
            for (int j = 0; j < 4; j++) {
                //设置单元格的样式
                row.createCell(j).setCellStyle(style_content);
            }
        }

        //设置单元格的值(固定的文本内容)
        //设置标题内容,注意单元格必须创建出来后才能设置
        sheet.getRow(0).getCell(0).setCellValue(sheetName);              //标题文本
        sheet.getRow(2).getCell(0).setCellValue(supplierOrCustomer);      //供应商文本（前边已创建过，故get即可）
        sheet.getRow(3).getCell(0).setCellValue("下单日期");
        sheet.getRow(3).getCell(2).setCellValue("经办人");
        sheet.getRow(4).getCell(0).setCellValue("审核日期");
        sheet.getRow(4).getCell(2).setCellValue("经办人");
        sheet.getRow(5).getCell(0).setCellValue("采购日期");
        sheet.getRow(5).getCell(2).setCellValue("经办人");
        sheet.getRow(6).getCell(0).setCellValue("入库日期");
        sheet.getRow(6).getCell(2).setCellValue("经办人");
        sheet.getRow(7).getCell(0).setCellValue("订单明细");
        sheet.getRow(8).getCell(0).setCellValue("商品名称");
        sheet.getRow(8).getCell(1).setCellValue("数量");
        sheet.getRow(8).getCell(2).setCellValue("价格");
        sheet.getRow(8).getCell(3).setCellValue("金额");

        //设置行高和列宽
        sheet.getRow(0).setHeight((short) 1000);   //设置标题行高
        for (int i = 2; i < 12; i++) {
            sheet.getRow(i).setHeight((short) 500);         //设置内容行高
        }
        //设置列宽
        for (int i = 0; i < 4; i++) {
            sheet.setColumnWidth(i, 5000);
        }

        //设置日期格式
        //订单表内容中有下单、审核、采购、入库日期。我们也需要设置一下日期格式的显示
        HSSFCellStyle style_date = wb.createCellStyle();
        style_date.cloneStyleFrom(style_content);            //日期格式基本上与内容格式一致，故从内容格式中copy一份
        HSSFDataFormat dataFormat = wb.createDataFormat();   //设置日期格式
        style_date.setDataFormat(dataFormat.getFormat("yyyy-MM-dd hh:mm"));
        for (int i = 3; i < 7; i++) {
            sheet.getRow(i).getCell(1).setCellStyle(style_date);
        }

        //设置内容
        //供应商名称
        String supplierName = supplierDao.getName(orders.getSupplieruuid(), new HashMap<>(), "getName");
        sheet.getRow(2).getCell(1).setCellValue(supplierName);
        //订单详情-设置日期与经办人
        if (orders.getCreatetime() != null) {
            sheet.getRow(3).getCell(1).setCellValue(orders.getCreatetime());
        }
        if (orders.getChecktime() != null) {
            sheet.getRow(4).getCell(1).setCellValue(orders.getChecktime());
        }
        if (orders.getStarttime() != null) {
            sheet.getRow(5).getCell(1).setCellValue(orders.getStarttime());
        }
        if (orders.getEndtime() != null) {
            sheet.getRow(6).getCell(1).setCellValue(orders.getEndtime());
        }
        Map<Long, String> nameMap = new HashMap<>();
        String createrName = empDao.getName(orders.getCreater(), nameMap, "getName");
        String checkerName = empDao.getName(orders.getChecker(), nameMap, "getName");
        String starterName = empDao.getName(orders.getStarter(), nameMap, "getName");
        String enderName = empDao.getName(orders.getEnder(), nameMap, "getName");
        sheet.getRow(3).getCell(3).setCellValue(createrName);
        sheet.getRow(4).getCell(3).setCellValue(checkerName);
        sheet.getRow(5).getCell(3).setCellValue(starterName);
        sheet.getRow(6).getCell(3).setCellValue(enderName);

        //设置订单明细内容
        int index = 0;
        Orderdetail od = null;
        for (int i = 9; i < rowCount; i++) {
            od = detailList.get(index);
            row = sheet.getRow(i);
            row.getCell(0).setCellValue(od.getGoodsname());
            row.getCell(1).setCellValue(od.getNum());
            row.getCell(2).setCellValue(od.getPrice());
            row.getCell(3).setCellValue(od.getMoney());
            index++;
        }
        //设置合计
        sheet.getRow(rowCount).getCell(0).setCellValue("合计");
        sheet.getRow(rowCount).getCell(3).setCellValue(orders.getTotalmoney());

        //写到输出流里去
        try {
            wb.write(os);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                wb.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void exportByTemplate(OutputStream os, Long uuid) {
        Orders orders = ordersDao.get(uuid);
        List<Emp> empList = empDao.getList(null, null, null);
        Map<Long, String> empNameMap = new HashMap<>();
        for (Emp emp : empList) {
            empNameMap.put(emp.getUuid(), emp.getName());
        }
        //模板替换有点像EL表达式或OGNL表达式的用法
        Map<String, Object> dataMap = new HashMap<>();
        String type = orders.getType();
        dataMap.put("type", "1".equals(type) ? "采购单" : "销售单");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        dataMap.put("o", orders);
        dataMap.put("emp", empNameMap);
        dataMap.put("sdf", sdf);
        dataMap.put("suppliername", supplierDao.get(orders.getSupplieruuid()).getName());
        HSSFWorkbook wk = null;
        try {
            wk = new HSSFWorkbook(new ClassPathResource("export_orders.xls").getInputStream());
            XLSTransformer transformer = new XLSTransformer();
            transformer.transformWorkbook(wk, dataMap);
            wk.write(os);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (wk != null) {
                try {
                    wk.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 根据运单号获取运单详情(调用webservice提供的服务)
     *
     * @param sn
     * @return
     */
    @Override
    public List<Waybilldetail> waybilldetailList(Long sn) {
        return waybillWs.waybilldetailList(sn);
    }
}
